package com.chuangyiruanke.util;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class EncryptUtil {

  /**
   * 使用 AES 加密
   *
   * @param key       加密密钥
   * @param plainText 明文数据
   * @return
   * @throws GeneralSecurityException
   */
  public static byte[] encryptUsingAES(byte[] key, String plainText) throws GeneralSecurityException {
    return encryptUsingAES(key, plainText, StandardCharsets.UTF_8);
  }

  /**
   * 使用 AES 加密
   *
   * @param key         加密密钥
   * @param plainText   明文数据
   * @param charsetName 文本编码
   * @return
   * @throws GeneralSecurityException
   */
  public static byte[] encryptUsingAES(byte[] key, String plainText, String charsetName) throws GeneralSecurityException {
    return encryptUsingAES(key, plainText, Charset.forName(charsetName));
  }

  /**
   * 使用 AES 加密
   *
   * @param key       加密密钥
   * @param plainText 明文数据
   * @param charset   文本编码
   * @return
   * @throws GeneralSecurityException
   */
  public static byte[] encryptUsingAES(byte[] key, String plainText, Charset charset) throws GeneralSecurityException {
    byte[] content = plainText.getBytes(charset);
    return encryptUsingAES(key, content);
  }
  /**
   * 使用 AES 加密
   *
   * @param key       加密密钥
   * @param plainData 明文数据
   * @return
   * @throws GeneralSecurityException
   */
  public static byte[] encryptUsingAES(byte[] key, byte[] plainData) throws GeneralSecurityException {
    SecretKey secretKey = new SecretKeySpec(key, "AES");
    //6.根据指定算法AES自成密码器
    Cipher cipher = Cipher.getInstance("AES/ECB/Pkcs5Padding");
    //7.初始化密码器，第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作，第二个参数为使用的KEY
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    //8.解密
    return cipher.doFinal(plainData);
  }

  /**
   * 使用 AES/ECB/Pkcs5Padding 解密
   *
   * @param key              解密密钥
   * @param encryptedHexText 十六进制编码的加密内容
   * @return
   * @throws GeneralSecurityException
   */
  public static byte[] decryptUsingAES(byte[] key, String encryptedHexText) throws GeneralSecurityException {
    return decryptUsingAES(key, StringUtils.toByteArray(encryptedHexText));
  }

  /**
   * 使用 AES/ECB/Pkcs5Padding 解密
   *
   * @param key       解密密钥
   * @param encrypted 加密内容
   * @return
   * @throws GeneralSecurityException
   */
  public static byte[] decryptUsingAES(byte[] key, byte[] encrypted) throws GeneralSecurityException {
    SecretKey secretKey = new SecretKeySpec(key, "AES");
    //6.根据指定算法AES自成密码器
    Cipher cipher = Cipher.getInstance("AES/ECB/Pkcs5Padding");
    //7.初始化密码器，第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作，第二个参数为使用的KEY
    cipher.init(Cipher.DECRYPT_MODE, secretKey);
    //8.解密
    return cipher.doFinal(encrypted);
  }

  /**
   * 使用 RSA 加密
   *
   * @param privateKeyStr    私钥
   * @param encryptedHexText 十六进制编码的已加密内容
   * @return
   * @throws GeneralSecurityException
   */
  public static byte[] rsaDecrypt(String privateKeyStr, String encryptedHexText) throws GeneralSecurityException {
    return rsaDecrypt(privateKeyStr, StringUtils.toByteArray(encryptedHexText));
  }

  /**
   * 使用 RSA 加密
   *
   * @param privateKeyStr 私钥
   * @param encrypted     加密内容
   * @return
   * @throws GeneralSecurityException
   */
  public static byte[] rsaDecrypt(String privateKeyStr, byte[] encrypted) throws GeneralSecurityException {
    byte[] keyBytes = Base64.getDecoder().decode(privateKeyStr.replaceAll("\n", ""));
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    return cipher.doFinal(encrypted);
  }

  /**
   * 使用 RSA 加密
   *
   * @param publicKeyStr 公钥文本
   * @param plainText    明文数据
   * @return
   * @throws GeneralSecurityException
   */
  public static byte[] rsaEncrypt(String publicKeyStr, String plainText) throws GeneralSecurityException {
    return rsaEncrypt(publicKeyStr, plainText, StandardCharsets.UTF_8);
  }

  /**
   * 使用 RSA 加密
   *
   * @param publicKeyStr 公钥文本
   * @param plainText    明文数据
   * @param charsetName  文本编码
   * @return
   * @throws GeneralSecurityException
   */
  public static byte[] rsaEncrypt(String publicKeyStr, String plainText, String charsetName) throws GeneralSecurityException {
    return rsaEncrypt(publicKeyStr, plainText, Charset.forName(charsetName));
  }

  /**
   * 使用 RSA 加密
   *
   * @param publicKeyStr 公钥文本
   * @param plainText    明文数据
   * @param charset      文本编码
   * @return
   * @throws GeneralSecurityException
   */
  public static byte[] rsaEncrypt(String publicKeyStr, String plainText, Charset charset) throws GeneralSecurityException {
    return rsaEncrypt(publicKeyStr, plainText.getBytes(charset));
  }

  /**
   * 使用 RSA 加密
   *
   * @param publicKeyStr 公钥文本
   * @param plainData    明文数据
   * @return
   * @throws GeneralSecurityException
   */
  public static byte[] rsaEncrypt(String publicKeyStr, byte[] plainData) throws GeneralSecurityException {
    byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr.replaceAll("\n", ""));
    X509EncodedKeySpec pkcs8KeySpec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey publicKey = keyFactory.generatePublic(pkcs8KeySpec);
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    return cipher.doFinal(plainData);
  }

  public static byte[] rsaSign(String privateKeyStr, String algorithm, byte[] content) throws GeneralSecurityException {
    byte[] keyBytes = Base64.getDecoder().decode(privateKeyStr.replaceAll("\n", ""));
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
    Signature signature = Signature.getInstance("MD5WithRSA");
    signature.initSign(privateKey);
    signature.update(content);
    return signature.sign();
  }

  /**
   * 使用公钥检查私钥签名
   *
   * @param publicKeyStr 公钥文本
   * @param content      对其进行签名的数据
   * @param hexSignText  十六进制编码的数据签名
   * @return
   * @throws GeneralSecurityException
   */
  public static boolean checkRSASign(String publicKeyStr, byte[] content, String hexSignText) throws GeneralSecurityException {
    return checkRSASign(publicKeyStr, content, StringUtils.toByteArray(hexSignText));
  }

  /**
   * 使用公钥检查私钥签名
   *
   * @param publicKeyStr 公钥文本
   * @param content      对其进行签名的数据
   * @param sign         数据签名
   * @return
   * @throws GeneralSecurityException
   */
  public static boolean checkRSASign(String publicKeyStr, byte[] content, byte[] sign) throws GeneralSecurityException {
    byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr.replaceAll("\n", ""));
    X509EncodedKeySpec pkcs8KeySpec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey publicKey = keyFactory.generatePublic(pkcs8KeySpec);

    java.security.Signature signature = java.security.Signature.getInstance("MD5WithRSA");

    signature.initVerify(publicKey);
    signature.update(content);
    return signature.verify(sign);
  }
}
